// The MIT License (MIT)
// Copyright (c) 2011 Akiyoshi Ochiai
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to 
// deal in the Software without restriction, including without limitation the 
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is 
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in 
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// 

#include "char_converter.h"

#include <stdexcept>

#include <errno.h>

namespace speech_recog_julius {

namespace {

static int const kDefaultBufferSize = 128;

} // end namespace 


CharConverter::CharConverter(std::string const& from_encoding,
                             std::string const& to_encoding)
    : buffer_(kDefaultBufferSize) {
  handle_ = ::iconv_open(to_encoding.c_str(), from_encoding.c_str());
  if (reinterpret_cast< ::iconv_t >(-1) == handle_) {
    throw std::runtime_error("iconv_open failed()");
  }
}


CharConverter::~CharConverter() {
  ::iconv_close(handle_);
}


std::string CharConverter::Convert(std::string const& input) {
  // iconv() doesn't mutate the internal buffer
  char* input_ptr = const_cast<char*>(input.data()); 
  std::size_t input_len = input.size();
  while (1) {
    char* output_ptr = &buffer_[0];
    std::size_t output_len = buffer_.size();
    std::size_t result = ::iconv(handle_, 
                                 &input_ptr, &input_len,
                                 &output_ptr, &output_len);
    if (static_cast<std::size_t>(-1) == result) {
      switch (errno) {
        case E2BIG:
          buffer_.resize(buffer_.size() * 2, '\0');
        case EILSEQ:
          throw std::runtime_error("Input contains invalid multibyte sequence");
        case EINVAL:
          throw std::runtime_error("Input contains malformed multibyte sequence.");
        default:
          throw std::logic_error("Unknown iconv error!");
      }
    } else {
      return std::string(&buffer_[0], output_ptr);
      break;
    }
  }
}


} // end namespace speech_recog_julius
